/*
 * ChannelTransceiver.hpp
 *
 *  Created on: Nov 2, 2013
 *      Author: vladimir
 */

#ifndef CHANNELTRANSCEIVER_HPP_
#define CHANNELTRANSCEIVER_HPP_

#include <memory>
#include <functional>
#include <typeinfo>
#include <string>
#include <type_traits>

namespace mq
{

struct IpcTranceiverIface;

class ChannelTransceiver
{
	template< typename T >
	friend inline void RegisterToMessage(
			ChannelTransceiver& trxObject,
			const unsigned int id,
			const std::function< void(const T&) > & cb );


public:

	typedef std::function< void(const char*) > 		GenericCbType;
	typedef std::shared_ptr< IpcTranceiverIface > 	IpcTranceiverPtr;


	ChannelTransceiver( IpcTranceiverPtr ipcTranceiver );
	~ChannelTransceiver();


	template< typename T >
	void SendMessage( const T& msg );
	bool ReceiveMessage();

private:

	void RegisterMsgHandler(
			const unsigned int id,
			const std::string type,
			const GenericCbType & cb );
	void SendTheMessageToChannel(
			const char * data,
			const unsigned int dataSize );


	struct Imp;
	std::unique_ptr<Imp> pimpl;
};


template< typename T >
inline
void RegisterToMessage(
		ChannelTransceiver& trxObject,
		const unsigned int id,
		const std::function< void(const T&) > & cb )
{
	static_assert( std::is_standard_layout<T>::value, "has to be standard type" );

	trxObject.RegisterMsgHandler(
			id,
			typeid(T).name(),
			[cb](const char *data){ cb( *reinterpret_cast<const T*>(data) ); }
		);
}

template< typename T >
void ChannelTransceiver::SendMessage( const T& msg )
{
	static_assert( std::is_standard_layout<T>::value, "has to be standard type" );

	SendTheMessageToChannel( reinterpret_cast< const char* >( & msg ), sizeof( msg ) );
}

} /* namespace mq */

#endif /* CHANNELTRANSCEIVER_HPP_ */
